import time
import sys
import numpy as np
import subprocess
import os
import random
from pathlib import Path
from switchboard import PySbPacket, PySbTx, PySbRx, SbDut, binary_run

THIS_DIR = Path(__file__).resolve().parent

TV = [
    # addr, data, op
    (0x8000_0010, 0x8000_0010, 1), # 0
    (0x8000_0020, 0xBADD_F00D, 1), # 1
    (0x8000_0030, 0xFEE1_DEAD, 1), # 2
    (0x8000_0020, 0x0000_0000, 0), # 3
    (0x8000_0020, 0xDEAD_FA11, 1), # 4
    (0x8000_0010, 0x0000_0000, 0), # 5
    (0x8000_0020, 0x0000_0000, 0), # 6
    (0x8000_0030, 0x0000_0000, 0), # 7  
]

def get_request(idx:int) -> tuple[int,int,int]:
    (addr,data,op) = TV[idx]
    return (addr,data,op)

def send_to_axi(addr:int, data:int, tx:PySbTx, op:int): # op{0:read, 1:write}
    txp = PySbPacket(
        destination=0x3f3f3f3f,
        flags=1,
        data=np.arange(5, dtype=np.uint8)
    )
    txp.destination = addr
    txp.data[0] = (data >> 24) & 0x0000_00ff
    txp.data[1] = (data >> 16) & 0x0000_00ff
    txp.data[2] = (data >> 8) & 0x0000_00ff
    txp.data[3] = (data >> 0) & 0x0000_00ff
    txp.data[4] = op;
    print("SB: send txp to axi:")
    print(f"addr = {addr:x} data = {data:x} op = {op}")
    tx.send(txp)
    
def receive_from_axi(rx:PySbRx) -> tuple[int,int,int]:
    rxp = rx.recv()
    if not rxp:
        print("SB: No receive")
        return (0x0,0x0)
    else:
        tmp0 = int(rxp.data[0])
        tmp1 = int(rxp.data[1])
        tmp2 = int(rxp.data[2])
        tmp3 = int(rxp.data[3])
        data = (tmp0 << 24) | (tmp1 << 16) | (tmp2 << 8) | tmp3
        addr = rxp.destination
        valid = int(rxp.data[4])
        print("SB: receive rxp from axi:")
        print(f"addr = {addr:x} data = {data:x} valid = {valid}")
        return (addr,data,valid)

def main():
    tx = PySbTx('from_sb_to_axil.q', fresh=True)
    rx = PySbRx('from_axil_to_sb.q', fresh=True)
    subprocess.run(["xvlog","--sv","axil_interface.sv"])
    subprocess.run(["xvlog","--sv","axil_ram.v"])
    subprocess.run(["xvlog","--sv","dpi_interface.sv"])
    subprocess.run(["xvlog","--sv","axil_dpi_top_module.sv"])
    subprocess.run(["xelab","-debug" ,"all" ,"--snapshot" ,"sp1" ,"axil_dpi_top_module"])
    xsim_process = subprocess.Popen(["xsim", "sp1"], stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE, text=True)
    xsim_process.stdin.write("open_vcd\n")
    xsim_process.stdin.write("log_vcd *\n")
    xsim_process.stdin.write("add_wave *\n")
    xsim_process.stdin.write("run 50ns\n")   
    
    client = binary_run(THIS_DIR / 'client')
    time.sleep(1)
    
    for i in range(8):
        xsim_process.stdin.write("run 200ns\n")
        xsim_process.stdin.flush()  
    retcode = client.wait()
    # tx = PySbTx('from_sb_to_axil.q', fresh=True)
    # rx = PySbRx('from_axil_to_sb.q', fresh=True)
    
    # for i in range(len(TV)):
    #     print(f"SB: test vector[{i}]")
    #     req_addr,req_data,req_op = get_request(i)
    #     send_to_axi(req_addr,req_data,tx,req_op)
        
    #     xsim_process.stdin.write("run 200ns\n")
    #     xsim_process.stdin.flush()
        
    #     resp_addr,resp_data,resp_valid = receive_from_axi(rx)
        
    #     xsim_process.stdin.write("run 200ns\n")
    #     xsim_process.stdin.flush()
        
    #     input("Press any key to continue the simulation.")
    
    xsim_process.stdin.write("close_vcd\n")
    xsim_process.stdin.write("quit\n")
    xsim_process.communicate() 
    
    print("SB: simulation end")

main()
        